home *** CD-ROM | disk | FTP | other *** search
/ System Booster / System Booster.iso / Archives / Drivers / vc_2_2.lha / ParNet / Source / pio.asm < prev    next >
Assembly Source File  |  1994-11-01  |  22KB  |  792 lines

  1. **
  2. ** $Header: SRC:CVSROOT/Vector/ParNet/pio.asm,v 1.1.1.1 1994/06/23 02:39:40 Barnard Exp $
  3. **
  4.  
  5. **
  6. ** This code was originally written by Matthew Dillon and put into Public Domain
  7. **
  8. ** All changes concerning the adaption of Matt's original code to the
  9. ** Vector Connection I/O board are © 1991-1994 by Henning Schmiedehausen
  10. ** All rights for this changes are reserved. The original code is Public Domain
  11. **
  12. ** This code is distributed with the expressed written permission of Matthew
  13. ** Dillon (Thank you very much, Matt)
  14. **
  15. **
  16.  
  17.         ;   PARALLEL PORT NETWORK LOW LEVEL ROUTINES
  18.         ;
  19.         ;   CABLE:  Connect D7-D0,SEL,POUT, and BUSY across,
  20.         ;        Connect ACK to SEL locally:
  21.         ;        Connect GND lines indicated
  22.         ;
  23.         ;   (2-9)   D7-D0   ------------    D7-D0
  24.         ;   (12)    POUT    ------------    POUT
  25.         ;   (11)    BUSY    ------------    BUSY       PARALLEL PORT
  26.         ;   (13)    SEL     --+------+--    SEL
  27.         ;   (10)    ACK     -/        \-    ACK
  28.         ;   (18-22) GND     ------------    GND
  29.         ;
  30.         ;   WARNING: you cannot connect RI on the serial port to your
  31.         ;         modem because it interferes with the parallel
  32.         ;         port's SEL line in this configuration.
  33.         ;
  34.         ;   *    28K/sec bandwidth
  35.         ;   *    # machines depends on extra hardware for buffering,
  36.         ;    but 3 ought to work fine without any extra hardware.
  37.         ;
  38.         ;    (network protocol can now handle 254)
  39.         ;
  40.         ;   Data Line Definitions:
  41.         ;    CIAA PORTB :    D7-D0    used for byte data transfer
  42.         ;    CIAB PORTA :    D2-D0    used for line aquisition and
  43.         ;                handshaking (SEL,POUT,BUSY)
  44.         ;
  45.         ;   All lines pulled up.  Thus, asserted state is a 0.    Idle
  46.         ;   state is an undriven (1).  Protocol transfers a byte at
  47.         ;   a time.  Protocol is ethernet style with a small window
  48.         ;   of error in the line aquisition routine.
  49.         ;
  50.         ;   Note:   Timeouts should be set around a second.  Ideally
  51.         ;        defaults should be fixed on faster machines.
  52.         ;
  53.         ;   CIAB PORTA    D0  ~ACK    hand shake
  54.         ;        D1  ~REQ    hand shake
  55.         ;        D2   CTL    1 = special byte, 0 = data byte.
  56.         ;                (for address mark, valid when ~REQ
  57.         ;                 goes low.    For EOP mark, sample
  58.         ;                 when ~REQ goes high)
  59.         ;
  60.         ;                PROTOCOL
  61.         ;
  62.         ;   HandShake    (Reader <- Writer transfer).  A Handshake
  63.         ;        sequence transfers TWO bytes of information.
  64.         ;
  65.         ;        WRITER                READER
  66.         ;    |-> place data, ~REQ->0
  67.         ;    |                 wait for ~REQ->0
  68.         ;    |                 read data & store
  69.         ;    |                 set ~ACK->0
  70.         ;    |   wait ~ACK->0
  71.         ;    |   place data, ~REQ->1
  72.         ;    |                 wait for ~REQ->1
  73.         ;    |                 read data & store
  74.         ;    |                 set ~ACK->1
  75.         ;    |   wait ~ACK->1
  76.         ;    |<- LOOP  (2 bytes written)      LOOP  (2 bytes read)
  77.         ;
  78.         ;
  79.         ;   Read:   (1) Determine if your machine is being addressed
  80.         ;        (~REQ=0, data=myaddress, CTL=1)
  81.         ;        (1) set DDR for ~ACK to output and
  82.         ;        (2) Handshake sequence for the address mark, only
  83.         ;        first byte valid.
  84.         ;        (3) Handshake sequence for data util rcv byte
  85.         ;        with CTL = 1 (EOP), byte must == 0.
  86.         ;        (4) Set ~ACK (bit 0) to input
  87.         ;
  88.         ;   Write:  (1) AQUIRE THE NETWORK (see below)
  89.         ;        involves gaining control and then setting the
  90.         ;        DDR for CTL and ~REQ to outputs.
  91.         ;
  92.         ;        Also checks if somebody is writing to us,
  93.         ;        in which case -2 is returned instantaniously
  94.         ;        indicating we should do a ParRead().
  95.         ;
  96.         ;        (2) Handshake sequence for address mark, send dest
  97.         ;        address (second byte garbage).  Note that CTL->1
  98.         ;        *BEFORE* we set ~REQ->0
  99.         ;        (3) Handshake sequence for data bytes
  100.         ;        (4) Handshake sequence for EOP mark (Note that CTL->1
  101.         ;        *AFTER* we get the ~ACK->1 and before release
  102.         ;        ~REQ (->1).  Only firstbyte valid and set to 0.
  103.         ;
  104.         ;        (5) Set ~ACK and ~CTL to inputs
  105.         ;
  106.         ;   AQUIRE: Line aquisition prevents two people from writing to
  107.         ;        the net at the same time.
  108.         ;
  109.         ;        * A line is considered aquired if ANY of the 3
  110.         ;          control lines is 0.
  111.         ;        * If network is not aquired:
  112.         ;        - set ~ACK to output and 1
  113.         ;        - bclr ~ACK to 0 and bne success
  114.         ;          (else set ~ACK to input and try again)
  115.         ;        - set data lines to output and place my address
  116.         ;          (Must ]be done before CTL is glitched)
  117.         ;        - set ~CTL to output and 1
  118.         ;        - set CTL to 0 and then 1 (glitch it) to cause
  119.         ;          FLAG interrupt on all other machines
  120.         ;        - set ~REQ to output and 0 (beginning of handshake
  121.         ;          sequence)
  122.         ;        - lastly, release ~ACK by setting it to an input
  123.         ;
  124.         ;          Note that at all times at least one line is a 0
  125.         ;          so no other machine will attempt to aquire the net.
  126.         ;
  127.         ;   Note that the destination address is placed on the data
  128.         ;   lines after we have aquired the line but before we glitch
  129.         ;   the CTL line to cause an interrupt.  This allows the
  130.         ;   other machines to instantaniously determine who is being
  131.         ;   addressed.
  132.         ;
  133.         ;   Note that the CTL line gets glitched at the end of a packet
  134.         ;   too for the EOP mark.  In this case there is a 0 on the
  135.         ;   data lines so while an interrupt is generated, nobody
  136.         ;   thinks they are being addressed.
  137.  
  138.         INCLUDE "exec/types.i"
  139.         INCLUDE "exec/execbase.i"
  140.         INCLUDE "exec/io.i"
  141.  
  142.         INCLUDE "vector/vectorpar.i"
  143.  
  144. PORTA        set    1
  145. ; PORTB        set    1
  146.  
  147.         ifd    PORTA
  148.  
  149. CTL_MASK    equ    %11010000        ; Kontrolleitungen für Port A
  150. PIOIntBit    equ    0
  151.  
  152.         BITDEF    PIO,ACK,6
  153.         BITDEF    PIO,REQ,7
  154.         BITDEF    PIO,CTL,4
  155.  
  156.         endc
  157.  
  158.         ifd    PORTB
  159.  
  160. CTL_MASK    equ    %00000111        ; Kontrolleitungen für Port B
  161. PIOIntBit    equ    2
  162.  
  163.         BITDEF  PIO,ACK,2
  164.         BITDEF  PIO,REQ,1
  165.         BITDEF  PIO,CTL,0
  166.  
  167.         endc
  168.  
  169.  
  170.         xdef    PIOIntBit
  171.  
  172.         XREF    _intena
  173.  
  174. DISABLE     MACRO
  175.         MOVE.W    #$04000,_intena     *(NOT IF_SETCLR)+IF_INTEN
  176.         ADDQ.B    #1,IDNestCnt(A6)
  177.         ENDM
  178.  
  179. ENABLE        MACRO
  180.         SUBQ.B    #1,IDNestCnt(A6)
  181.         BGE.S    ENABLE\@
  182.         MOVE.W    #$0C000,_intena     *IF_SETCLR+IF_INTEN
  183. ENABLE\@
  184.         ENDM
  185.  
  186.  
  187.         section __MERGED,DATA
  188.  
  189.         xdef    _ParLLTimeout
  190.         xdef    _ParCollision1
  191.         xdef    _ParCollision2
  192.         xdef    _ParDebug
  193.  
  194.         ;   Note, the timeout is set manually on init by using the
  195.         ;   timer.device to time one second.
  196.  
  197. _ParLLTimeout    dc.l    1000000     ; default timeout value (count). 1 second
  198. _ParNetAddr    dc.b    0        ; default network address (msb 4 bits)
  199. _DummyBuf    dc.b    0        ; dummy buffer
  200.         dc.b    0        ; dummy buffer
  201.         dc.b    0        ; pad
  202. _ParCollision1    dc.l    0        ; statistics
  203. _ParCollision2    dc.l    0        ;
  204. Null        dc.l    0        ; always 0
  205.         dc.l    0        ; always 0
  206.  
  207. _ParDebug    ds.l    16        ; 16 longword debug entries
  208.  
  209.         section text,code
  210.  
  211.         ;   (void) ParAddress(myaddr)
  212.         ;    Set my address to (1-254)
  213.         ;
  214.         ;    0 and 255 are reserved!
  215.         ;
  216.         ;   int  = ParDataReady()
  217.         ;    returns 1  if packet pending
  218.         ;    returns 0  if line is currently idle
  219.         ;    returns -1 if packet isn't for you
  220.         ;
  221.         ;    if line has been aquired but no control address has been
  222.         ;    put on it yet, ParDataReady() will wait for a control
  223.         ;    address.  Thus, after a signal, a single call to
  224.         ;    ParDataReady() should suffice.
  225.         ;
  226.         ;   n = ParReadV (buf1, bytes1, buf2, bytes2, ..., NULL, NULL);
  227.         ;    (buffer sizes must be even)
  228.         ;   n = ParRead (buf, bytes)
  229.         ;    read a pending packet.    Returns n = -1 (1 second timeout
  230.         ;    no packet pending), n = 0 to bytes -1 (1 second timeout
  231.         ;    after transmission interrupted), n = bytes (success),
  232.         ;    or n > bytes (transmitting machine's packet was larger
  233.         ;    than we can handle, extra bytes thrown out)
  234.         ;
  235.         ;    NOTE: requesting an odd number of bytes is O.K. but
  236.         ;          if you request N where N is odd and the writer
  237.         ;          sends N + 1 you will never know (N will be
  238.         ;          returned).  See ParWrite() below
  239.         ;
  240.         ;   n = ParWriteV (destadr, buf1, bytes1, buf2, bytes2, ..., NULL, NULL);
  241.         ;    (buffer sizes must be even)
  242.         ;   n = ParWrite(destadr, buf, bytes)
  243.         ;    write a packet.  Returns:
  244.         ;    n = -2    Cannot write anything, a packet is pending
  245.         ;        (instantanious)
  246.         ;    n = -1    Destination machine does not respond (1 sec to)
  247.         ;    n = N    N bytes written ok (success if n == bytes)
  248.         ;
  249.         ;    NOTE: sending an odd number of bytes is O.K. but if
  250.         ;    you write N where N is odd and the reader requests
  251.         ;    N + 1 he will get N + 1 the last byte being garbage.
  252.         ;
  253.         xdef    _SetUpPIO
  254.         xdef    _ParRead
  255.         xdef    _ParReadV
  256.         xdef    _ParWrite
  257.         xdef    _ParWriteV
  258.         xdef    _ParAddress
  259.         xdef    _ParDataReady
  260.         xdef    _LongCheckSum
  261.         xdef    _Time10000
  262.  
  263.         xref    _UnitBase        ; Kommen von CMD_INACTIVE
  264.         xref    _PIOBase
  265.  
  266. ; ***********************************************************************
  267. ;
  268. ; PIO spezifischer Code
  269. ;
  270. ; ***********************************************************************
  271.  
  272. ;
  273. ; SetUpPio stellt die PIO auf die richtige Betriebsart
  274. ;
  275.  
  276. _SetUpPIO:    move.l    _UnitBase,a1        ; Zeiger auf den Kanal holen
  277.             move.b    #0,PIOR_DDR(a1)        ; Alles Eingänge
  278.  
  279.             move.b    #%10000000,PIOR_PCR(a1)    ; Port auf Bitmode schalten
  280.  
  281.             move.l    _PIOBase,a1        ; Port C holen
  282.             move.b    PIO_PCDDR(a1),d0
  283.             and.b    #~CTL_MASK,d0
  284.             move.b    d0,PIO_PCDDR(a1)    ; Control-Leitungen auf Input schalten
  285.  
  286.             rts
  287.  
  288.  
  289. _ParAddress:    move.l    4(sp),D0                ;   address 1-254
  290.         move.b    D0,_ParNetAddr        ;   store
  291.         rts
  292.  
  293.         ;   ParDataReady()
  294.         ;
  295.         ;   -1    packet isn't for you
  296.         ;   0    line is idle
  297.         ;   1    packet probably pending for you
  298.  
  299. _ParDataReady:    move.l    d2,-(a7)
  300.         move.l    _UnitBase,A0        ; Basis-Adresse des Kanals holen
  301.         lea    PIOR_PDR(A0),A0        ; a0 zeigt auf Port
  302.         move.l    _PIOBase,a1        ; Basis-Adresse der PIO holen
  303.         lea    PIO_PCDR(a1),a1        ; a1 zeigt auf den Port C
  304.  
  305. .pdstable    move.b    (A1),D0
  306.         and.b    #CTL_MASK,d0        ; Nur die Kontrolleitungen interessieren
  307.  
  308.         move.b    (A0),D1
  309.  
  310.         move.b    (A1),d2
  311.         and.b    #CTL_MASK,d2
  312.         cmp.b    d2,D0                  ;   control lines stable?
  313.         bne    .pdstable
  314.  
  315.         ;   Now, ParDataReady might be called after the sending machine
  316.         ;   has aquired but before it can assert REQ.  However, the
  317.         ;   sending machine has already (guarenteed) placed its address
  318.         ;   on the data port.  So while the address matches, loop while
  319.         ;   REQ not asserted.
  320.  
  321.         btst.l    #PIOB_REQ,D0        ;   ~Req asserted?
  322.         beq    .pd10            ;   beq yes
  323.         cmp.b    _ParNetAddr,D1        ;   no, does data match anyway?
  324.         beq    .pdstable        ;   YES, loop until get ~REQ or
  325.         bra    .pdfail         ;   data bad.
  326.  
  327. .pd10        btst.l    #PIOB_CTL,D0        ;   yes, Ctl ?
  328.         beq    .pdrn            ;   no, middle of some packet
  329.         cmp.b    _ParNetAddr,D1        ;   yes, my address?
  330.         bne    .pdrn
  331.         moveq.l #1,D0            ;   yes, packet (probably) for us
  332.         move.l    (a7)+,d2
  333.         rts
  334.  
  335. .pdfail     btst.l    #PIOB_CTL,D0        ;   fail due to ~Req not asserted
  336.         beq    .pdrn            ;   Ctl = 0, line busy
  337. .pdr0        moveq.l #0,D0            ;   line idle
  338.         move.l    (a7)+,d2
  339.         rts
  340. .pdrn        moveq.l #-1,D0            ;   line busy, packet not for me
  341.         move.l    (a7)+,d2
  342.         rts
  343.  
  344. _ParReadV:                    ;   Read Into Vector
  345.         movem.l D2-D7/A2-A5,-(sp)
  346.         lea    12+40(sp),A3
  347.         bra    .rm000
  348.  
  349. _ParRead:
  350.         movem.l D2-D7/A2-A5,-(sp)
  351.         lea    Null,A3         ;   Pointer to next vector
  352. .rm000        move.l    4+40(sp),A0             ;   A0 = buffer to read into
  353.         move.l    8+40(sp),D7             ;   D7 = # bytes to read (maximum)
  354.         move.l    _UnitBase,a1        ; A1 zeigt auf Unit
  355.         lea    PIOR_DDR(a1),a2        ; A2 zeigt auf DATA-DDR
  356.         lea    PIOR_PDR(a1),a1        ; A1 zeigt auf DATA
  357.  
  358.         move.l    _PIOBase,a4        ; A4 zeigt auf PIO
  359.         lea    PIO_PCDDR(a4),a5    ; A5 zeigt auf CTL-DDR
  360.         lea    PIO_PCDR(a4),a4        ; A4 zeigt auf CTL
  361.  
  362.         move.b    #0,(A2)                 ;   ensure all are inputs
  363.         bclr.b    #PIOB_ACK,(A5)
  364.         bclr.b    #PIOB_REQ,(A5)
  365.         bclr.b    #PIOB_CTL,(A5)
  366.  
  367.         move.l    _ParLLTimeout,D5    ;   D5 = timeout load
  368.         moveq.l #-1,D6            ;   D6 = # bytes read so far
  369.  
  370.         ;   WAIT LOOK FOR ADDRESS MARK
  371.         ;
  372.         ;   Ctl = 1, ~DReq = 0
  373.  
  374.         move.l    D5,D4            ;   D4 = timeout countdown
  375. .rmstab     move.b    (A4),D0                 ;   control data
  376.         and.b    #CTL_MASK,d0        ; Nur Kontrolleitungen
  377.         move.b    (A1),D1                 ;   data data (network addr)
  378.         move.b    (a4),d2
  379.         and.b    #CTL_MASK,d2
  380.         cmp.b    d2,D0
  381.         bne    .rmstab
  382.         btst.l    #PIOB_CTL,D0        ;   expect CTL = 1
  383.         beq    .rms1            ;   nope
  384.         btst.l    #PIOB_REQ,D0        ;   expect ~REQ = 0
  385.         beq    .rms2            ;   yes
  386. .rms1
  387.         add.l    #1,_ParDebug+0
  388.         subq.l    #1,D4            ;   timeout
  389.         bne    .rmstab
  390.         bra    .rmend            ;   no address mark!
  391.  
  392. .rms2        cmp.b    _ParNetAddr,D1        ;   my address?
  393.         bne    .rms1            ;   no, timeout loop
  394.  
  395.         ;   My address, ~Ack byte.
  396.  
  397.         bclr.b    #PIOB_ACK,(A4)           ;   set ~ACK to 0
  398.         bset.b    #PIOB_ACK,(A5)           ;   set to output
  399.  
  400.         move.l    D5,D4            ;   reset timeout
  401. .rms4        btst.b    #PIOB_REQ,(A4)           ;   wait for ~REQ to go away
  402.         bne    .rms5
  403.         add.l    #1,_ParDebug+4
  404.         subq.l    #1,D4
  405.         bne    .rms4
  406.         moveq.l #-2,D6            ;   ~REQ not released ?????
  407.         bra    .rmend
  408.  
  409. .rms5        bset.b    #PIOB_ACK,(A4)           ;   release ~ACK
  410.         moveq.l #0,D6            ;   set # bytes read to 0
  411.         bra    .rms10            ;   skip past move
  412.  
  413.         ;   MAIN READ LOOP
  414.         ;
  415.         ;   D6 holds cnt, A0 buffer ptr, D0-D4 free to allocate
  416.  
  417. .rms10loop
  418.         move.b    D0,(A0)                 ;   store data
  419.         addq.l    #1,A0            ;   next addr.
  420.  
  421. .rms10        btst.b    #PIOB_REQ,(A4)           ;   wait for ~REQ asserted
  422.         beq    .rms20
  423.         btst.b    #PIOB_REQ,(A4)
  424.         beq    .rms20
  425.         move.l    D5,D4            ;   load timeout
  426. .rms11        btst.b    #PIOB_REQ,(A4)           ;   wait for ~REQ asserted w/to
  427.         beq    .rms20
  428.         add.l    #1,_ParDebug+8
  429.         subq.l    #1,D4
  430.         bne    .rms11
  431.         bra    .rmend
  432.  
  433. .rms20        move.b    (A1),D0                 ;   get data and
  434.         bclr.b    #PIOB_ACK,(A4)           ;   assert ~ACK
  435.  
  436.         ;   note, on CTL = 1 end sequence this data item is a dummy
  437.  
  438.         move.b    D0,(A0)                 ;   store data
  439.         addq.l    #1,A0            ;   next addr.
  440.         addq.l    #2,D6            ;   optimized but not quite
  441.                         ;   true, we've only written 1 sf.
  442.         btst.b    #PIOB_REQ,(A4)           ;   wait for ~REQ released
  443.         bne    .rms30
  444.         btst.b    #PIOB_REQ,(A4)
  445.         bne    .rms30
  446.         move.l    D5,D4
  447. .rms21        btst.b    #PIOB_REQ,(A4)           ;   wait for ~REQ rel w/ to
  448.         bne    .rms30
  449.         add.l    #1,_ParDebug+12
  450.         subq.l    #1,D4
  451.         bne    .rms21
  452.         bra    .rmendsub        ;   sub because D6 is 2 ahead
  453.  
  454. .rms30        move.b    (A1),D0                 ;   get data
  455.         move.b    (A4),D1                 ;   get CTL status
  456.         bset.b    #PIOB_ACK,(A4)           ;   release ~ACK
  457.         btst.l    #PIOB_CTL,D1            ;   EOP if CTL = 1
  458.         bne    .rmeop
  459.  
  460.         ;   CANNOT STORE DATA HERE!  In case odd # bytes requested,
  461.         ;   second byte would overflow buffer
  462.  
  463.         subq.l    #2,D7            ;   # bytes remaining
  464.         bgt    .rms10loop
  465.         bne    .rmnlb
  466.         move.b    D0,(A0)                 ;   if D7 = 0 its even and we
  467.                         ;   should store the last byte
  468. .rmnlb        cmp.l    #-1,D7            ;   -1 = was odd #
  469.         bne    .rmeven         ;   fixup count
  470.         subq.l    #1,D6
  471.  
  472. .rmeven
  473. .rmsev0     tst.l    (A3)                    ;   if next buffer NULL
  474.         beq    .rmovflow
  475.         move.l    (A3)+,A0                ;   next buffer
  476.         move.l    (A3)+,D7
  477.         beq    .rmsev0         ;   0 bytes, goto next buffer
  478.         bra    .rms10            ;   loop, continue reading
  479.  
  480. .rmovflow
  481.         lea    _DummyBuf,A0        ;   overflow, dummy buffer
  482.         bra    .rms10
  483.  
  484. .rmeop        tst.b    D0            ;   EOP data better be 0!
  485.         beq    .rmendsub
  486.         moveq.l #-3,D6
  487.         bra    .rmend
  488.  
  489. .rmendsub    subq.l    #2,D6            ;   because we were two ahead
  490.  
  491. .rmend        bset.b    #PIOB_ACK,(A4)           ;   active pull up before (?)
  492.         bclr.b    #PIOB_ACK,(A5)           ;   setting ~ACK to input
  493.         move.l    D6,D0            ;   return value
  494.         movem.l (sp)+,D2-D7/A2-A5       ;   restore registers
  495.         rts
  496.  
  497. _ParWriteV:    movem.l D2-D7/A2-A6,-(sp)       ;   write vector
  498.         lea    16+44(sp),A3
  499.         bra    .wm000
  500.  
  501. _ParWrite:
  502.         movem.l D2-D7/A2-A6,-(sp)
  503.         lea    Null,A3
  504. .wm000        move.l    4+44(sp),D3             ;   D3 = destination address
  505.         move.l    8+44(sp),A0             ;   A0 = buffer to write
  506.         move.l    12+44(sp),D7            ;   D7 = # bytes to write
  507.  
  508.         move.l    _UnitBase,a1        ; A1 zeigt auf Unit
  509.         lea    PIOR_DDR(a1),a2        ; A2 zeigt auf DATA-DDR
  510.         lea    PIOR_PDR(a1),a1        ; A1 zeigt auf DATA
  511.  
  512.         move.l    _PIOBase,a4        ; A4 zeigt auf PIO
  513.         lea    PIO_PCDDR(a4),a5    ; A5 zeigt auf CTL-DDR
  514.         lea    PIO_PCDR(a4),a4        ; A4 zeigt auf CTL
  515.  
  516.         move.l    4,A6            ;   SYSBase
  517.  
  518.         move.b    #0,(A2)
  519.         and.b    #~CTL_MASK,(A5)
  520.  
  521.         move.l    _ParLLTimeout,D5    ;   D5 = timeout load
  522.  
  523.         move.l    D5,D4            ;   D4 = timeout countdown
  524.         moveq.l #-2,D6            ;   D6 = # bytes written
  525.  
  526.         ;   AQUIRE THE LINE USING ~ACK
  527.  
  528. .wmstab
  529.         bset.b    #PIOB_ACK,(A4)           ;   so is a 1 when we set it to w
  530.  
  531.         DISABLE
  532.  
  533.         move.b    (A4),D0                 ;   get stable data
  534.         and.b    #CTL_MASK,d0
  535.         move.b    (A1),D1
  536.         move.b    (a4),d2
  537.         and.b    #CTL_MASK,d2
  538.         cmp.b    d2,D0
  539.         beq    .wmstab1
  540.  
  541.         ENABLE
  542.  
  543.         bra    .wmstab
  544.  
  545.         ;   Ints still disabled
  546.         ;   D0 holds ~ACK ~REQ CTL status
  547.  
  548. .wmstab1    and.b    #CTL_MASK,D0        ;   ~ACK=1, ~REQ=1, CTL=1
  549.         cmp.b    #CTL_MASK,D0
  550.         beq    .wm02
  551.  
  552.         ;   no, if CTL = 1, ~REQ = 0, and D1 = my address then
  553.         ;   return w/ -2
  554.  
  555.         btst.l    #PIOB_REQ,D0
  556.         bne    .wm01
  557.         btst.l    #PIOB_CTL,D0
  558.         beq    .wm01
  559.         cmp.b    _ParNetAddr,D1        ;   somebody calling me?
  560.         bne    .wm01
  561.  
  562.         ENABLE
  563.         bra    .wmend
  564.  
  565. .wm01
  566.         ENABLE
  567.  
  568.         add.l    #1,_ParDebug+16
  569.         subq.l    #1,D4
  570.         bne    .wmstab
  571.         bra    .wmend
  572.  
  573.         ;   interrupts still disabled
  574.         ;   we almost own the line
  575.  
  576. .wm02        bset.b    #PIOB_ACK,(A5)                ;   set ~ACK to an output
  577.         nop
  578.         bclr.b    #PIOB_ACK,(A4)                ;   assert ~ACK
  579.         bne    .wm05            ;   was released before, have line!
  580.  
  581.                         ;   don't have line,
  582.         bclr.b    #PIOB_ACK,(A5)                ;   set back to input
  583.         bra    .wm01
  584.  
  585.         ;   Line now aquired.
  586.  
  587. .wm05
  588.         ENABLE
  589.  
  590.         move.b    #%11111111,(A2)         ;   set data ddr to outputs
  591.         move.b    D3,(A1)                 ;   set data lines to our addr
  592.  
  593.         ;   Before asserting ~REQ pulse CTL to cause interrupt on remote
  594.         ;   machines.  Note that our address is already on the data
  595.         ;   lines.
  596.  
  597.         bset.b    #PIOB_CTL,(A5)           ;   set CTL to output
  598.         bclr.b    #PIOB_CTL,(A4)           ;   pulse CTL to cause FLAG int
  599.         or.b    #CTL_MASK,(A4)          ;   set CTL = 1 and make sure
  600.                         ;   REQ will be one when we
  601.         bset.b    #PIOB_REQ,(A5)           ;   set ~REQ to output
  602.  
  603.         bclr.b    #PIOB_REQ,(A4)           ;   assert ~REQ
  604.  
  605.         bclr.b    #PIOB_ACK,(A5)           ;   make ~ACK an input
  606.                         ;   (note that REQ->0 before ACK->release)
  607.  
  608.         moveq.l #-1,D6            ;   D6 = # bytes written
  609.  
  610.         ;   INTERRUPTS ENABLED FOR TXFER (fully handshaked)
  611.         ;
  612.         ;   Address mark ~ACK, wait for ~ACK asserted
  613.  
  614. .wm10        btst.b    #PIOB_ACK,(A4)
  615.         beq    .wm15
  616.         move.l    D5,D4            ;   D4 = timeout countdown
  617. .wm11        btst.b    #PIOB_ACK,(A4)
  618.         beq    .wm15
  619.         add.l    #1,_ParDebug+20
  620.         subq.l    #1,D4
  621.         bne    .wm11
  622.         bra    .wmend
  623.  
  624.         ;   got ack, now set CTL = 0 (leaves at least one line 0 so
  625.         ;   nobody else thinks the bus is idle!)
  626.         ;
  627.         ;   note:   Since this is the address mark, and is sampled by
  628.         ;        the reader before it asserts ~ACK, I can set CTL
  629.         ;        = 0 now instead of waiting till after ~ACK is
  630.         ;        released.
  631.  
  632. .wm15        bclr.b    #PIOB_CTL,(A4)           ;   set CTL = 0 for duration of pkt
  633.         nop                ;   ???
  634.         bset.b    #PIOB_REQ,(A4)           ;   release ~REQ
  635.  
  636.  
  637.         moveq.l #0,D6            ;   # bytes written
  638.  
  639.         ;   DATA XFER LOOP
  640.         ;
  641.         ;   wait for ~ACK to be released (->1).  If no more bytes
  642.         ;   then skip to .wm50
  643.  
  644. .wm20
  645.         tst.l    D7            ;   more data in this buffer?
  646.         ble    .wm50            ;   nope.
  647.  
  648.         btst.b    #PIOB_ACK,(A4)           ;   wait ~ACK released
  649.         bne    .wm30
  650.         move.l    D5,D4            ;   D4 = timeout countdown
  651. .wm21        btst.b    #PIOB_ACK,(A4)
  652.         bne    .wm30            ;   need the timeout here?
  653.         btst.b    #PIOB_ACK,(A4)
  654.         bne    .wm30
  655.         add.l    #1,_ParDebug+24
  656.         subq.l    #1,D4
  657.         bne    .wm21
  658.         bra    .wmend
  659.  
  660.         ;   Assert ~REQ for this data byte and wait for ~ACK
  661.  
  662. .wm30
  663.         move.b    (A0)+,D0                ;   get next data byte
  664.         move.b    D0,(A1)                 ;   store data and
  665.         bclr.b    #PIOB_REQ,(A4)           ;   assert ~REQ
  666.  
  667.         move.b    (A0)+,D0                ;   get next data byte
  668.         subq.l    #2,D7            ;   one less byte (this and next)
  669.         addq.l    #1,D6            ;   # bytes written (this only)
  670.                         ;   (not valid until we get ACK
  671.                         ;    which is why the wmendsub
  672.  
  673.         btst.b    #PIOB_ACK,(A4)           ;   wait for ACK
  674.         beq    .wm40
  675.         btst.b    #PIOB_ACK,(A4)
  676.         beq    .wm40
  677.         move.l    D5,D4            ;   D4 = timeout countdown
  678. .wm31        btst.b    #PIOB_ACK,(A4)
  679.         beq    .wm40
  680.         add.l    #1,_ParDebug+28
  681.         subq.l    #1,D4
  682.         bne    .wm31
  683.         bra    .wmendsub
  684.  
  685.         ;   Have ~ACK, byte transmitted.  ++bytes written, --bytes left
  686.         ;   and loop
  687.  
  688. .wm40        move.b    D0,(A1)                 ;   store second byte
  689.         bset.b    #PIOB_REQ,(A4)           ;   release ~REQ
  690.  
  691.         addq.l    #1,D6            ;   # bytes written
  692.  
  693.         bra    .wm20
  694.  
  695.         ;   Last byte in buffer has been transmitted.
  696.         ;
  697.         ;   Get next buffer in vector
  698.  
  699. .wm50        tst.l    (A3)
  700.         beq    .wm50a
  701.         move.l    (A3)+,A0                ;   buffer ptr
  702.         move.l    (A3)+,D7                ;   # bytes
  703.         bra    .wm20            ;   loop to top
  704.  
  705. .wm50a
  706.         ;   Last byte has been transmitted,
  707.         ;
  708.         ;   Wait for ~ACK to be released and then assert ~REQ with
  709.         ;   EOP & CTL = 1
  710.         ;
  711.         ;   (timing on read is that CTL is sampled when ~REQ is
  712.         ;   RELEASED so no timing window here)
  713.  
  714.         btst.b    #PIOB_ACK,(A4)           ;   Wait ~ACK released
  715.         beq    .wm50
  716.  
  717.         move.b    #0,(A1)                 ;   EOP mark (0)
  718.         bclr.b    #PIOB_REQ,(A4)           ;   assert ~REQ
  719.  
  720.         ;   Wait for ~ACK asserted
  721.  
  722.         btst.b    #PIOB_ACK,(A4)
  723.         beq    .wm60
  724.         move.l    D5,D4
  725. .wm51        btst.b    #PIOB_ACK,(A4)
  726.         beq    .wm60
  727.         add.l    #1,_ParDebug+32
  728.         subq.l    #1,D4
  729.         bne    .wm51
  730.         moveq.l #-3,D6            ;   EOP failed
  731.         bra    .wmend
  732.  
  733.         ;   Set CTL = 1 then release ~REQ, then wait for ~ACK released
  734.  
  735. .wm60        or.b    #PIOF_CTL,(A4)          ;   set CTL = 1
  736.         or.b    #PIOF_CTL!PIOF_REQ,(A4) ;   release ~REQ
  737.  
  738.         ;   Wait ~ACK released ?
  739.  
  740. .wm61        btst.b    #PIOB_ACK,(A4)
  741.         beq    .wm61
  742.  
  743.         ;   Add D7 to D6.  This handles fixup if an odd number of bytes
  744.         ;   were requested written, D7 will be -1 (odd) or 0 (even) and
  745.         ;   D6 will be one too large (odd) or perfect (even)
  746.  
  747.         add.l    D7,D6
  748.  
  749.         bra    .wmend
  750.  
  751. .wmendsub    subq.l    #1,D6        ;   was ahead in count
  752.  
  753. .wmend        move.b    #0,(A2)         ;   set data port to input
  754.         and.b    #~CTL_MASK,(A5) ;   set data port for ctl lines to input
  755.  
  756.         move.l    D6,D0            ;   return value
  757.         movem.l (sp)+,D2-D7/A2-A6       ;   restore registers
  758.         rts
  759.  
  760.         ;   sum = LongCheckSum(buf, bytes)
  761.         ;   (buffer must be lw aligned and bytes must be multiples of 4)
  762.  
  763. _LongCheckSum:
  764.         moveq.l #0,D0            ;   D0 = accumulated checksum
  765.         move.l    4(sp),A0                ;   A0 = ptr
  766.         move.l    8(sp),D1                ;   D1 = bytes
  767.         beq    .pcrts
  768. .pc10        add.l    (A0)+,D0
  769.         subq.l    #4,D1
  770.         bgt    .pc10
  771.         tst.l    D1
  772.         bne    .pc20            ;   not multiple of 4 bytes!
  773. .pcrts        rts                ;   return checksum
  774. .pc20        illegal             ;   cause task-held msg
  775.         rts
  776.  
  777.         ;   Delays 10000 rough timeout loops, used to determine
  778.         ;   timeout on init
  779.  
  780. _Time10000:
  781.         move.l    #10000,D4
  782. t10        move.l    D4,D4
  783.         move.l    D4,D4
  784.         move.l    D4,D4
  785.         move.l    D4,D4
  786.         subq.l    #1,D4
  787.         bne    t10
  788.         rts
  789.  
  790.         END
  791.  
  792.